package scala40rules;

import java.util.logging.Logger;


public class Scale extends CardSet {

	
	private CardSet myScale;
	private CardSet prototypeScale;

	
	public Scale(CardSet cardSet){
		this.myScale = cardSet;
		this.prototypeScale = new CardSet();
		SymbolList symbolList = new SymbolList();
		for(int i=0; i<symbolList.size()-1; i++){
			Card card = new Card();
			card.setOrdinalValue(i+1);
            card.setSymbol(symbolList.getSymbol(i));
            card.setSuit("noSuit");
			prototypeScale.addCard(card);
		}
		Card card = new Card();
		card.setOrdinalValue(1);
        card.setSymbol("A");
        card.setSuit("noSuit");
		prototypeScale.addCard(card);
	}
	
	
	public CardSet getMyScale() {
		return myScale;
	}

	
	public void setMyScale(CardSet myScale) {
		this.myScale = myScale;
	}
	
	
	public int size(){
		return this.myScale.size();
	}
	
	
	private boolean respectPrototypeAsc(){
		System.out.println("\n\n SONO IN ASC");
		boolean result = true;
		int indicePrototype = 0;
		int i=0;
		boolean aligned=false;
		try{
			while( (i<this.myScale.size()) && (!aligned) ){
				//myScale[1]==prototype[i] oppure myScale[i] e' Jolly
				 System.out.print("[Scale] confronto ["+this.myScale.getCard(i).getOrdinalValue()+"] con ["+prototypeScale.getCard(indicePrototype).getOrdinalValue()+"]");
				
				
				if (this.myScale.getCard(i).isJoker()){
						indicePrototype++;
						i++;
						System.out.println(" --> FALSE >");
				}else{ 
						// allineo le due scale
						if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
							indicePrototype++;
							System.out.println(" --> FALSE >");
						}
						else{
							System.out.println(" --> ALIGNED ");
							aligned=true;
						}
				}
			}
			while( i<this.myScale.size()){
				System.out.print("[Scale] confronto ["+this.myScale.getCard(i).getOrdinalValue()+"] con ["+prototypeScale.getCard(indicePrototype).getOrdinalValue()+"]");
				if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
						||
						this.myScale.getCard(i).getOrdinalValue() == 14){
							indicePrototype++;
							i++;
							System.out.println(" --> TRUE");
				}else{
							System.out.println(" --> FALSE >");
							result = false;
							return result;
				}
			}			
			result=true;
			return result;
		}catch(IndexOutOfBoundsException e){
			System.out.println("[Scale] outOfBound ");
			return false;
		}
	}


	private boolean respectPrototypeDesc(){
		System.out.println(" \n\n SONO IN DESC ");
		boolean result = true;
		int indicePrototype = 0;
		int i= this.myScale.size()-1;
		boolean aligned=false;
		try{
			while( (i>=0) && (!aligned) ){
				//myScale[1]==prototype[i] oppure myScale[i] e' Jolly
				System.out.print("[Scale] confronto ["+this.myScale.getCard(i).getOrdinalValue()+"] con ["+prototypeScale.getCard(indicePrototype).getOrdinalValue()+"]");
				
				
				if (this.myScale.getCard(i).isJoker()){
						indicePrototype++;
						i--;
						System.out.println(" --> FALSE <");
				}else{ 
						// allineo le due scale
						if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
							indicePrototype++;
							System.out.println(" --> FALSE <");
						}
						else{
							System.out.println(" --> ALIGNED ");
							aligned=true;
						}
				}
			}
			while( i>=0){
				System.out.print("[Scale] confronto ["+this.myScale.getCard(i).getOrdinalValue()+"] con ["+prototypeScale.getCard(indicePrototype).getOrdinalValue()+"]");
				if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
						||
						this.myScale.getCard(i).getOrdinalValue() == 14){
							indicePrototype++;
							i--;
							System.out.println(" --> TRUE");
				}else{
							System.out.println(" --> FALSE <");
							result = false;
							return result;
				}
			}			
			result=true;
			return result;
		}catch(IndexOutOfBoundsException e){
			System.out.println("[Scale] outOfBound ");
			return false;
		}
	}


	private boolean isSameSuit(){
		boolean result=true;
		for(int i=0; i< this.myScale.size(); i++){
			for(int j=0; j<this.myScale.size(); j++){
			result &= (
					(this.myScale.getCard(i).getSuit().equalsIgnoreCase(this.myScale.getCard(j).getSuit()))
					||
					(this.myScale.getCard(i).getOrdinalValue()==14)
					||
					(this.myScale.getCard(j).getOrdinalValue()==14)
					);
			}
		}
		if(result){System.out.println("[Scale] isSameSuit = TRUE");}else{System.out.println("[Scale] isSameSuit = FALSE");}
		return result;
	}
		
	
	private boolean isRightSize(){
		boolean result = (this.myScale.size() >= 3) && (this.myScale.size() <= 6);
		if(result){System.out.println("[Scale] isRightSize = TRUE");}else{System.out.println("[Scale] isRightSize = FALSE");}
		return result;
	}


	public boolean isValidScale(){
		boolean result = false;
		if(this.isRightSize()){
            if(this.isSameSuit()){
                if(!this.isAllJokers()){
                    result = this.respectPrototypeAsc();
                    if(!result){
                        result = this.respectPrototypeDesc();
                    }
                }
            }
        }
        if(result)
        	 this.printScale("STAMPA RICHIESTA DA isValidScale()\nsumScaleValue: "+this.sumScaleValue());
//			System.out.println("[Scale || isValidScale()] isSameSuit: "+this.isSameSuit());
//			System.out.println("[Scale || isValidScale()] isAllJokers: "+this.isAllJokers());
//			System.out.println("[Scale || isValidScale()] e' una scala : "+this.respectPrototypeAsc() +" "+ this.respectPrototypeDesc() );
		return result;
	}


	public int getOffset(){
		boolean result = true;
		int indicePrototype = 0;
		int i=0;
		int offset=0;
		while( i<this.myScale.size()){
			//myScale[1]==prototype[i] oppure myScale[i] e' Jolly
			//System.out.print("[Scale] confronto ["+this.myScale.getCard(i).getOrdinalValue()+"] con ["+prototypeScale.getCard(indicePrototype).getOrdinalValue()+"]");
			
			if((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
				||
				this.myScale.getCard(i).getOrdinalValue() == 14){
					indicePrototype++;
					i++;
					//System.out.println(" --> TRUE");
			}else{
				//System.out.println(" --> FALSE");
				if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
					indicePrototype++;
					offset++;
					
				}
				else{
					i++;
				}
			}
		}
		return offset;
	}


	public boolean isInRange(Card card, int offset){
//		System.out.println(" card ordinal value "+card.getOrdinalValue()+
//				" prototipo ordinal value inizio "+ prototypeScale.getCard(offset).getOrdinalValue() +
//				" prototipo ordinal value fine "+prototypeScale.getCard(offset + myScale.size()-1).getOrdinalValue()); 
		return ( card.getOrdinalValue()>= prototypeScale.getCard(offset).getOrdinalValue())
				&&
				( card.getOrdinalValue() <= prototypeScale.getCard(offset + myScale.size()-1).getOrdinalValue());
	}


	public CardSet tryToSubstitute(Card card){
        int matteInTesta = 0;
		boolean result = true;
		int indicePrototype = 0;
		int i = 0;
        int substitutePosition = -1;
		boolean aligned = false;
		String suit="";


        //ASC searching
		try{
			while( (i<this.myScale.size()) && (!aligned) ){

				//myScale[1]==prototype[i] oppure myScale[i] e' Jolly
				if (this.myScale.getCard(i).isJoker()){
						indicePrototype++;
						i++;
                        matteInTesta++;
				}else{
					suit=this.myScale.getCard(i).getSuit();
						// allineo le due scale
						if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
							indicePrototype++;
						}
						else{
							aligned=true;
						}
				}
			}
            for(int j=matteInTesta; j>0; j--){
                //se matta da sostiruire e' tra quelle in testa alla scala
                if(card.getOrdinalValue()==prototypeScale.getCard(indicePrototype-j).getOrdinalValue()){
                    substitutePosition = i-j;
                    result = true;
                }
            }
			while( i<this.myScale.size() && result){
				if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
						||
						this.myScale.getCard(i).getOrdinalValue() == 14){
                            if((card.getOrdinalValue()==prototypeScale.getCard(indicePrototype).getOrdinalValue()) &&
                            		(card.getSuit().equalsIgnoreCase(suit))){
                                substitutePosition = i;
                            }
                            indicePrototype++;
							i++;
				}else{
							System.out.println(" --> FALSE >>");
							result = false;
				}
			}
        }
        catch(IndexOutOfBoundsException ioobe){
            System.out.println("[Scale || tryToSubstitute] outOfBound in ASC searching");
            result=false;
        }
        if(result  && (substitutePosition!=-1)){
            this.myScale.setCard(substitutePosition, card);
            return this.myScale;
        }

        try{
            //DESC searching
            matteInTesta = 0;
            result = true;
            indicePrototype = 0;
            i = this.myScale.size()-1;
            aligned = false;
            substitutePosition = -1;
                while( (i>=0) && (!aligned) ){

                    //myScale[1]==prototype[i] oppure myScale[i] e' Jolly
                    if (this.myScale.getCard(i).isJoker()){
                            indicePrototype++;
                            i--;
                            matteInTesta++;
                    }else{
                    	suit=this.myScale.getCard(i).getSuit();
                            // allineo le due scale
                            if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
                                indicePrototype++;
                            }
                            else{
                                aligned=true;
                            }
                    }
                }
                for(int j=matteInTesta; j>0; j--){
                     //se matta da sostiruire e' tra quelle in testa alla scala
                     if(card.getOrdinalValue()==prototypeScale.getCard(indicePrototype-j).getOrdinalValue()){
                            substitutePosition = i+j;
                            result = true;
                        }
                }
                while( i>=0 && result){
                    if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
                            ||
                            this.myScale.getCard(i).getOrdinalValue() == 14){
                                if((card.getOrdinalValue()==prototypeScale.getCard(indicePrototype).getOrdinalValue()) &&
                                		(card.getSuit().equalsIgnoreCase(suit))){
                                    substitutePosition = i;
                                }
                                indicePrototype++;
                                i--;
                    }else{
                                System.out.println(" --> FALSE <<");
                                result = false;
                    }
                }
                if(result && (substitutePosition!=-1)){
                    this.myScale.setCard(substitutePosition, card);
                    return this.myScale;
                }
            return null;
		}catch(IndexOutOfBoundsException e){
			System.out.println("[Scale || tryToSubstitute] outOfBound in DESC searching");
			return null;
		}
	}

	
	public CardSet tryToAdd(Card card){
		CardSet cardSet = new CardSet();
		for(int i=0; i<myScale.size(); i++){
			cardSet.addCard(myScale.getCard(i));
		}
		//aggiungo alla fine
		cardSet.addCard(card);
		System.out.println("\n[Scale tryToAdd] provo ad aggiungere ["+card.getOrdinalValue()+"] alla fine ");
		Scale firstScaleAttempt = new Scale(cardSet);
		if(firstScaleAttempt.isValidScale()){
            firstScaleAttempt.printScale(">>secondo il metodo CardSet.tryToAdd(), questa e' una scala valida");
			myScale.addCard(card);
		}
		else{
			//aggiungo all'inizio
			System.out.println("\n\n[Scale tryToAdd] provo ad aggiungere ["+card.getOrdinalValue()+"] all'inizio ");
			cardSet.removeCard(cardSet.size()-1);
			cardSet.addCard(0, card);
			Scale secondScaleAttempt = new Scale(cardSet);
			if(secondScaleAttempt.isValidScale()) {
                firstScaleAttempt.printScale("<<secondo il metodo CardSet.tryToAdd(), questa e' una scala valida");
				myScale.addCard(0, card);
			}
			else{
				cardSet=null;
			}
				
		}
		
		return cardSet;
	}


	private boolean isAllJokers() {
		int i=0;
		boolean joker=true;
		while(i<myScale.size() && joker){
			if (!(myScale.getCard(i).getOrdinalValue()==14)){
				return false;
			}
			i++;
		}
        if(joker){System.out.println("[Scale] isAllJoker = TRUE");}else{System.out.println("[Scale] isAllJoker = FALSE");}
		return joker;
	}


	private boolean containJoker(){
		for(int i=0; i<this.myScale.size(); i++){
			if(this.myScale.getCard(i).isJoker()){
				return true;
			}
		}
		return false;
	}


	private CardSet getEquivalentScaleWithoutJoker(){
        CardSet tempCardset = new CardSet();
        int matteInTesta = 0;
		boolean result = true;
		int indicePrototype = 0;
		int i = 0;
        int alignPosition=0;
		boolean aligned = false;
        int j=1000;

        //ASC searching
		try{
			while( (i<this.myScale.size()) && (!aligned) ){
				//myScale[1]==prototype[i] oppure myScale[i] e' Jolly
				if (this.myScale.getCard(i).isJoker()){
                    indicePrototype++;
                    i++;
                    matteInTesta++;
				}else{
                    // allineo le due scale
                    if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
                        indicePrototype++;
                    }
                    else{
                        aligned=true;
                        alignPosition=indicePrototype;
                    }
				}
			}
			while( i<this.myScale.size() && result){
				if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
						||
						this.myScale.getCard(i).getOrdinalValue() == 14){
                            indicePrototype++;
							i++;
				}else{
                    result = false;
				}
			}
        }
        catch(IndexOutOfBoundsException ioobe){
            System.out.println("[Scale || getEquivalentScaleWithoutJoker] outOfBound in ASC searching");
            result=false;
        }
			if(result){
                j=0;
                for(j=alignPosition-matteInTesta; j<indicePrototype; j++){
                    tempCardset.addCard(prototypeScale.getCard(j));
                }
                return tempCardset;
            }

            if(!result){
                System.out.println("scoperto che scala non e' ASC");
            }
        try{
            //DESC searching
            matteInTesta = 0;
            result = true;
            indicePrototype = 0;
            i = this.myScale.size()-1;
            aligned = false;
            alignPosition = 0;
            j=0;
                while( (i>=0) && (!aligned) ){
                    //myScale[1]==prototype[i] oppure myScale[i] e' Jolly
                    if (this.myScale.getCard(i).isJoker()){
                            indicePrototype++;
                            i--;
                            matteInTesta++;
                    }else{
                            // allineo le due scale
                            if(this.myScale.getCard(i).getOrdinalValue() > prototypeScale.getCard(indicePrototype).getOrdinalValue()){
                                indicePrototype++;
                            }
                            else{
                                aligned=true;
                                alignPosition=indicePrototype;
                            }
                    }
                }
                while(i>=0 && result){
                    if ((this.myScale.getCard(i).getOrdinalValue() == prototypeScale.getCard(indicePrototype).getOrdinalValue())
                            ||
                            this.myScale.getCard(i).getOrdinalValue() == 14){
                                indicePrototype++;
                                i--;
                    }else{
                        result = false;
                    }
                }
                if(result){
                    for(j=alignPosition-matteInTesta; j<indicePrototype; j++){
                        tempCardset.addCard(prototypeScale.getCard(j));
                    }
                    return tempCardset;
                }
            return null;
		}catch(IndexOutOfBoundsException e){
			System.out.println("[Scale || getEquivalentScaleWithoutJoker] outOfBound");
            System.out.println("matteInTesta:  - - - - "+matteInTesta);
            System.out.println("indicePrototype: - - - "+indicePrototype);
            System.out.println("result:  - - - - - - - "+result);
            System.out.println("i: - - - - - - - - - - "+i);
            System.out.println("j: - - - - - - - - - - "+j);
            System.out.println("aligned: - - - - - - - "+aligned);
            System.out.println("alignPosition: - - - - "+alignPosition);
            System.out.println("prototypeScale.size(): "+prototypeScale.size());
            System.out.println("tempCardset.size():  - "+tempCardset.size());
            System.out.println("myScale.size():  - - - "+this.myScale.size());
			return null;
		}
	}

	
	public int sumScaleValue(){
		CardSet tempScale = this.getMyScale();
		int first = 0;
		int last = this.size();
		int j;
		int result = 0;

		if(this.containJoker()){
			tempScale = this.getEquivalentScaleWithoutJoker();
		}

		
//		if(tempScale.size()==0){
//			System.out.println("[Scale] sumScaleValue(): scala vuota");
//			return 0;
//		}

		//gestisco eventuale [A][K][ecc] in testa alla scala
		if((tempScale.getCard(0).getOrdinalValue()==1) && (tempScale.getCard(1).getOrdinalValue()==13)){
			result+= 11;
			first++;
		}

		//gestisco eventuale [ecc][K][A] in coda alla scala
		if((tempScale.getCard(last-1).getOrdinalValue()==1) && (tempScale.getCard(last-2).getOrdinalValue()==13)){
			result+= 11;
			last--;
		}

		//sommo i valori delle carte della scala [tranne eventuali assi in testa o in coda]
		for (int i=first; i<last; i++){
			j = tempScale.getCard(i).getOrdinalValue();
			switch(j){
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
				case 6:
				case 7:
				case 8:
				case 9:
				case 10: result+= j; break;
				case 11:
				case 12:
				case 13: result+= 10; break;
				default: result+= 5000;
			}
		}
		
//		System.out.println("[Scale] sumScaleValue(): "+result);
		return result;
	}


    public void printScale(){
        this.printScale("NESSUN TITOLO");
    }

    
    public void printScale(String titolo){
        int symbolLenght = 8;
        int suitLenght = 8;
        int valueLenght = 7;
        System.out.println("\n\n"+titolo);
        System.out.println("[ SYMBOL |  SUIT  | VALUE ]");
        System.out.println("---------------------------");
        for(int i=0; i<this.myScale.size(); i++){
            System.out.print("[");
            System.out.print(getSpaces((symbolLenght - this.myScale.getCard(i).getSymbol().length())/2));
            System.out.print(this.myScale.getCard(i).getSymbol());
            System.out.print(getSpaces((symbolLenght - this.myScale.getCard(i).getSymbol().length())/2 + (symbolLenght - this.myScale.getCard(i).getSymbol().length())%2));
            System.out.print("|");
            System.out.print(getSpaces((suitLenght - this.myScale.getCard(i).getSuit().length())/2));
            System.out.print(this.myScale.getCard(i).getSuit());
            System.out.print(getSpaces((suitLenght - this.myScale.getCard(i).getSuit().length())/2 + (suitLenght - this.myScale.getCard(i).getSuit().length())%2));
            System.out.print("|");
            System.out.print(getSpaces((valueLenght - Integer.toString(this.myScale.getCard(i).getOrdinalValue()).length())/2));
            System.out.print(this.myScale.getCard(i).getOrdinalValue());
            System.out.print(getSpaces((valueLenght - Integer.toString(this.myScale.getCard(i).getOrdinalValue()).length())/2 + (valueLenght - Integer.toString(this.myScale.getCard(i).getOrdinalValue()).length())%2));
            System.out.println("]");
        }
        System.out.println("\n");
    }

}
